﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Cosmos.IL2CPU.Plugs;
using Assembler = Cosmos.Compiler.Assembler.Assembler;
using CPUx86 = Cosmos.Assembler.x86;

namespace Optimus
{
    [Plug(Target = typeof(HAL))]
    public class HALImpl
    {
        [Inline]
        public static UInt32 ReadErrorInfo()
        {
            new CPUx86.Mov
            {
                DestinationReg = CPUx86.Registers.EAX,
                SourceReg = CPUx86.Registers.EBP,
                SourceIsIndirect = true,
                SourceDisplacement = 0x00
            };
            new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX };
            return 0;
        }
        [Inline]
        public static UInt32 ReadEIPInfo()
        {
            //EIP
            new CPUx86.Mov
            {
                DestinationReg = CPUx86.Registers.EAX,
                SourceReg = CPUx86.Registers.EBP,
                SourceIsIndirect = true,
                SourceDisplacement = 0x04
            };
            new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX };
            return 0;
        }
        [Inline]
        public static UInt32 ReadCSInfo()
        {
            //EIP
            new CPUx86.Mov
            {
                DestinationReg = CPUx86.Registers.EAX,
                SourceReg = CPUx86.Registers.EBP,
                SourceIsIndirect = true,
                SourceDisplacement = 0x08
            };
            new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX };
            return 0;
        }
        [Inline]
        public static UInt32 ReadEFLAGSInfo()
        {
            //EIP
            new CPUx86.Mov
            {
                DestinationReg = CPUx86.Registers.EAX,
                SourceReg = CPUx86.Registers.EBP,
                SourceIsIndirect = true,
                SourceDisplacement = 0x0C
            };
            new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX };
            return 0;
        }
        [Inline]
        public static UInt32 GetEIP()
        {
            new CPUx86.Mov { DestinationReg  = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.ESP };
            new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX };
            return 0;
        }
        [Inline]
        public unsafe static void StartMultitask()
        {
            //EAX, __ISR_Handler_20_SetCS:ECX, EDX, EBX, ESP, EBP, ESI, EDI
            new CPUx86.Pushad();      
            new CPUx86.Push { DestinationReg = CPUx86.Registers.DS };
            new CPUx86.Push { DestinationReg = CPUx86.Registers.ES };
            new CPUx86.Push { DestinationReg = CPUx86.Registers.FS };
            new CPUx86.Push { DestinationReg = CPUx86.Registers.GS };

            new CPUx86.Mov { DestinationReg = CPUx86.Registers.AX, SourceValue = 0x10 };
            new CPUx86.Mov { DestinationReg = CPUx86.Registers.DS, SourceReg = CPUx86.Registers.AX};
            new CPUx86.Mov { DestinationReg = CPUx86.Registers.ES, SourceReg = CPUx86.Registers.AX };
            new CPUx86.Mov { DestinationReg = CPUx86.Registers.FS, SourceReg = CPUx86.Registers.AX };
            new CPUx86.Mov { DestinationReg = CPUx86.Registers.GS, SourceReg = CPUx86.Registers.AX };

            new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.ESP };
            new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX };

            new CPUx86.Call { DestinationLabel = "System_UInt32__Optimus_Manager_scheduler_System_UInt32_" };
            new CPUx86.Mov { DestinationReg = CPUx86.Registers.ESP, SourceReg = CPUx86.Registers.EAX };
    
            new CPUx86.Mov { DestinationReg = CPUx86.Registers.AL, SourceValue = 0x20 };
            new CPUx86.Mov { DestinationReg = CPUx86.Registers.EDX, SourceValue = 0x20 };
            new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceValue = 0x20 };
            new CPUx86.Out { DestinationReg = CPUx86.Registers.AL };
            
            new CPUx86.Pop { DestinationReg = CPUx86.Registers.GS };
            new CPUx86.Pop { DestinationReg = CPUx86.Registers.FS };
            new CPUx86.Pop { DestinationReg = CPUx86.Registers.ES };
            new CPUx86.Pop { DestinationReg = CPUx86.Registers.DS };

            new CPUx86.Popad();
            new CPUx86.IRETD();
        }
        [Inline]
        public unsafe static void StartMultitask2()
        {
            //EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI
            new CPUx86.Pushad();
            new CPUx86.Push { DestinationReg = CPUx86.Registers.DS };
            new CPUx86.Push { DestinationReg = CPUx86.Registers.ES };
            new CPUx86.Push { DestinationReg = CPUx86.Registers.FS };
            new CPUx86.Push { DestinationReg = CPUx86.Registers.GS };;

            new CPUx86.Mov  {DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.ESP };
            new CPUx86.Mov  {DestinationValue = 0x50C , DestinationIsIndirect = true, SourceReg = CPUx86.Registers.EAX };

           // new CPUx86.Call { DestinationLabel = "System_Void__Optimus_Manager_scheduler__" };
            new CPUx86.Mov { DestinationReg = CPUx86.Registers.ESP, SourceValue = 0x510 , SourceIsIndirect = true};

            new CPUx86.Mov { DestinationReg = CPUx86.Registers.AL, SourceValue = 0x20 };
            new CPUx86.Mov { DestinationReg = CPUx86.Registers.EDX, SourceValue = 0x20 };
            new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceValue = 0x20 };
            new CPUx86.Out { DestinationReg = CPUx86.Registers.AL };

            new CPUx86.Pop { DestinationReg = CPUx86.Registers.GS };
            new CPUx86.Pop { DestinationReg = CPUx86.Registers.FS };
            new CPUx86.Pop { DestinationReg = CPUx86.Registers.ES };
            new CPUx86.Pop { DestinationReg = CPUx86.Registers.DS };

            new CPUx86.Popad();
            new CPUx86.IRETD();
        }
        [Inline]
        public static void SwitchTo()
        {
            //EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI
            new CPUx86.ClrInterruptFlag();
            new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.CR0 };
            new CPUx86.Not { DestinationReg = CPUx86.Registers.AL};
            new CPUx86.Mov { DestinationReg = CPUx86.Registers.CR0, SourceReg = CPUx86.Registers.EAX };
            new CPUx86.Lidt { DestinationValue = 1023 ,DestinationIsIndirect = true };
            new CPUx86.Sti();
            new CPUx86.Mov { DestinationReg = CPUx86.Registers.AX, SourceValue = 0x4F02};
            new CPUx86.Mov { DestinationReg = CPUx86.Registers.BX , SourceValue = 0x105 };
            new CPUx86.INT { DestinationValue = 0x10 };
        }
        [Inline]
        public static void LoadAddress(UInt32 Value)
        {
            new CPUx86.Mov
            {
                DestinationReg = CPUx86.Registers.EAX,
                SourceReg = CPUx86.Registers.EBP,
                SourceIsIndirect = true,
                SourceDisplacement = 0x08
            };
            
           new CPUx86.Jump { DestinationReg = CPUx86.Registers.EAX};
        }
        [Inline]
        public static UInt32 SaveEAX()
        {
            new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX };
            new CPUx86.And { SourceValue = 0xFFFFFFFF, DestinationReg = CPUx86.Registers.EAX };
            return 0;
        }
        [Inline]
        public static UInt32 SaveEBX()
        {
            new CPUx86.And { SourceValue = 0xFFFFFFFF, DestinationReg = CPUx86.Registers.EBX };
            new CPUx86.Mov { SourceReg = CPUx86.Registers.EBX, DestinationReg = CPUx86.Registers.EAX };
            new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX };
            return 0;
        }   
        [Inline]
        public static UInt32 SaveECX()
        {
            new CPUx86.And { SourceValue = 0xFFFFFFFF, DestinationReg = CPUx86.Registers.ECX };
            new CPUx86.Mov { SourceReg = CPUx86.Registers.ECX, DestinationReg = CPUx86.Registers.EAX };
            new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX };
            return 0;
        }
        [Inline]
        public static UInt32 SaveEDX()
        {
            new CPUx86.And { SourceValue = 0xFFFFFFFF, DestinationReg = CPUx86.Registers.EDX };
            new CPUx86.Mov { SourceReg = CPUx86.Registers.EDX, DestinationReg = CPUx86.Registers.EAX };
            new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX };
            return 0;
        }
        [Inline]
        public static UInt32 SaveESP()
        {
            new CPUx86.And { SourceValue = 0xFFFFFFFF, DestinationReg = CPUx86.Registers.ESP };
            new CPUx86.Mov { SourceReg = CPUx86.Registers.ESP, DestinationReg = CPUx86.Registers.EAX };
            new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX };
            return 0;
        }
        [Inline]
        public static UInt32 SaveEBP()
        {
            new CPUx86.And { SourceValue = 0xFFFFFFFF, DestinationReg = CPUx86.Registers.EBP };
            new CPUx86.Mov { SourceReg = CPUx86.Registers.EBP, DestinationReg = CPUx86.Registers.EAX };
            new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX };
            return 0;
        }
        [Inline]
        public static UInt32 SaveESI()
        {
            new CPUx86.And { SourceValue = 0xFFFFFFFF, DestinationReg = CPUx86.Registers.ESI };
            new CPUx86.Mov { SourceReg = CPUx86.Registers.ESI, DestinationReg = CPUx86.Registers.EAX };
            new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX };
            return 0;
        }
        [Inline]
        public static UInt32 SaveEDI()
        {
            new CPUx86.And { SourceValue = 0xFFFFFFFF, DestinationReg = CPUx86.Registers.EDI };
            new CPUx86.Mov { SourceReg = CPUx86.Registers.EDI, DestinationReg = CPUx86.Registers.EAX };
            new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX };
            return 0;
        }
        [Inline]
        public static UInt32 Experiment(UInt32 Value)
        {
            new CPUx86.Mov
            {
                DestinationReg = CPUx86.Registers.EAX,
                SourceReg = CPUx86.Registers.EBP,
                SourceIsIndirect = true,
                SourceDisplacement = 0x08
            };
            new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX };
            return 0;
        }
        [Inline]
        public static UInt32 GetAddrOfDesktop()
        {
            new CPUx86.Mov
            {
                DestinationReg = CPUx86.Registers.EAX,
                SourceRef = Cosmos.Assembler.ElementReference.New("System_Void__Optimus_Manager_IdleTask__"),
                SourceIsIndirect = false
            };
            new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX };
            return 0;
        }


    }
}
